#include "functions.h"

extern int qMatrix [64];
extern unsigned char Code [32];
extern int blockSize;
extern float threshold;
extern float compressionScale;
extern int charsPerBlock;
extern int nBitsCode;
extern bool compressionJPG;
extern float sigmaNoise;
extern int quality;
extern string xorMask;

int main(int argc, char *argv[]) {
	const char* path_text = cimg_option("-f",(char*)"text.txt","Ruta y nombre del archivo de texto a esteganografiar y encriptar.");
	const char* path_img_in = cimg_option("-i",(char*)"../images/cameraman.jpg","Ruta y nombre de la imagen soporte.");
	const char* path_img_out = cimg_option("-o",(char*)"../images/esteg.bmp","Ruta y nombre de la imagen resultado.");
	CImg<float> eImg (path_img_in);
	loadConfig();
	unsigned int w = eImg.width(), h = eImg.height();
	//eImg.display();

	//if(!blockMultiple(eImg)) exit(1); //Controlamos el correcto lineamiento de la imagen.

	CImgList<> bases (blockSize*blockSize,blockSize,blockSize);
	CImg<float> oImg(eImg); // imagen original
	float E; 	// energía de cada bloque
	vector<float> vZig; 	// vector ordenado por zigzag
	vZig.resize(blockSize*blockSize);

//----------------------------------------
//Aca iria la encriptacion! La idea es que la nueva cadena tenga EL MISMO TAMANIO que esta (alrededor de 3100 caracteres), en una imagen de 256x256 entran 1024 subimagenes de 8x8, capaces de albergar hasta 2048 caracteres (#define charsPerBlock 2)
	char* pChar = loadText(path_text);
	//encriptyon(pChar);
	//printf("%s \n",pChar);
//----------------------------------------


	CImg<float> qMat(qMatrix,blockSize,blockSize,1,1); // levantamos la matriz de cuantificacion de Losheller
	qMat /= compressionScale;
	makeBase(bases); // armo las bases de coseno

	/*CImgDisplay window(bases, "Bases de coseno 8x8");
	while(!window.is_closed()){}*/

	//Armamos cada bloque de 8x8.
	int entran = 0;
	int pointer = 0;
	for(unsigned int i=0;i<w-(w%8);i+=blockSize){
		for(unsigned int j=0;j<h-(h%8);j+=blockSize){
			CImg<float> block(blockSize,blockSize),dctBlock(blockSize,blockSize);
			cimg_forXY(block,x,y){
				block(x,y) = eImg(i+x,j+y);
			}
			cimg_forXY(block,x,y){
				block(x,y) -= 128.;
			}
			dctBlock = DCT(block,bases,blockSize);
			E = norm2(dctBlock);
			//si la subimagen tiene la suficiente energia, guardo en ella algun caracter
			//cout<<"E: "<<E<<"  - i:"<<entran<<endl;
			if(th(E)){
				cimg_forXY(dctBlock,x,y){
					dctBlock(x,y) = dctBlock(x,y)/qMat(x,y);
					}
				zigZag(dctBlock,vZig,false);
				LSB(vZig,pChar,pointer);
				zigZag(dctBlock,vZig,true);
				cimg_forXY(dctBlock,x,y){
					dctBlock(x,y) = dctBlock(x,y)*qMat(x,y);
				}
				E = norm2(dctBlock); //luego de meter los datos, reviso q pasen el umbral
				if(th(E)){
					entran ++;
					pointer += charsPerBlock;
				}
				block = IDCT(dctBlock,bases,blockSize);

				cimg_forXY(block,x,y){
					eImg(i+x,j+y) = block(x,y) + 128.; //reasigno a la imagen
					if(eImg(i+x,j+y) < 0) eImg(i+x,j+y) = 0.;
					if(eImg(i+x,j+y) > 255) eImg(i+x,j+y) = 255.;
				}
			}
		}
	}
	cout << entran << " subimagenes pasan el umbral, lo que permite guardar: "<< entran*charsPerBlock << " caracteres, es decir: " <<entran*charsPerBlock*nBitsCode<<" bits ("<< entran*2*5/8 <<" bytes)" << endl;
	cout << "La imagen generada tiene un error de: " << oImg.MSE(eImg) <<endl;
	
	//si el usuario quiere ruido se lo agrego
	if(sigmaNoise > 0.)
		eImg.noise(sigmaNoise,0);

	//si el usuario quiere compresion, le agrego
	if(compressionJPG)
		eImg.save_jpeg(path_img_out,quality);
	else
		eImg.save_bmp(path_img_out);
	CImg<double> dif = (eImg-oImg).abs();
	dif.normalize(0.,255.).save_bmp("../images/dif.bmp");
	return 0;
}

